package com.atguigu.mall.search.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.atguigu.mall.search.config.ElasticsearchConfig;
import com.atguigu.mall.search.constant.IndexConst;
import com.atguigu.mall.search.service.MallSearchService;
import com.atguigu.mall.search.util.ElasticsearchUtil;
import com.atguigu.mall.search.vo.SearchParam;
import com.atguigu.mall.search.vo.SearchResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.lucene.search.join.ScoreMode;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.nested.NestedAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.List;

@Service
@Slf4j
public class MallSearchServiceImpl  implements MallSearchService {


    @Resource
    private RestHighLevelClient restHighLevelClient;
    @Override
    public SearchResult search(SearchParam searchParam) {

        SearchResponse searchResponse = null;
        SearchResult result = null;
        SearchRequest searchRequest = buildSearchRequest(searchParam);
        try {

            searchResponse = restHighLevelClient.search(searchRequest, ElasticsearchConfig.COMMON_OPTIONS);
            
             //分析响应数据
        } catch (IOException e) {
            e.printStackTrace();
        }

        return null;
    }


    /**
     * 构建 es 请求 参数
     * @param searchParam
     */
    private SearchRequest buildSearchRequest(SearchParam searchParam) {
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

        /**
         * 模糊匹配，过滤 （按照属性、分类、品牌、价格区间、库存）
         */
        /**
         * 标题
         */
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        String keyword = searchParam.getKeyword();
        if (StrUtil.isNotBlank(keyword)){
            MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery(IndexConst.PRODUCT_SKU_TITLE, keyword);
            boolQueryBuilder.must(matchQueryBuilder);
        }
        /**
         * 三级分类
         */
        Long catalog3Id = searchParam.getCatalog3Id();
        if (ObjectUtil.isNotNull(catalog3Id)){
            TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery(IndexConst.PRODUCT_CATALOG_ID, catalog3Id);
            boolQueryBuilder.filter(termQueryBuilder);
        }
        /**
         * 品牌ID
         */
        List<Long> brandIds = searchParam.getBrandId();
        if (CollUtil.isNotEmpty(brandIds)){
            TermsQueryBuilder termsQueryBuilder = QueryBuilders.termsQuery(IndexConst.PRODUCT_CATALOG_ID, brandIds);
            boolQueryBuilder.filter(termsQueryBuilder);
        }
        /**
         * 属性查询
         */
        List<String> attrs = searchParam.getAttrs();
        if (CollUtil.isNotEmpty(attrs)){
            attrs.forEach(attr->{
                BoolQueryBuilder nestedBoolQuery = QueryBuilders.boolQuery();
//          attr =》 1_5寸:8寸
                String[] attrArray = attr.split("_");
                String attrId = attrArray[0];
                String[] attrValues = attrArray[1].split(":");
                nestedBoolQuery.must(QueryBuilders.termQuery(IndexConst.PRODUCT_ATTR_ID,attrId));
                nestedBoolQuery.must(QueryBuilders.termsQuery(IndexConst.PRODUCT_ATTR_VALUE,attrValues));
                NestedQueryBuilder nestedQueryBuilder = QueryBuilders.nestedQuery("attrs", nestedBoolQuery, ScoreMode.None);
                boolQueryBuilder.filter(nestedQueryBuilder);
            });
        }
        /**
         * 库存查询
         */
        Integer hasStock = searchParam.getHasStock();
        TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery(IndexConst.PRODUCT_HAS_STOCK, hasStock == 1);
        boolQueryBuilder.filter(termQueryBuilder);

        /**
         * 价格区间
         */
        String skuPrice = searchParam.getSkuPrice();
        if (StrUtil.isNotBlank(skuPrice)){
            String[] priceArray = skuPrice.split("_");
            RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery(IndexConst.PRODUCT_SKU_PRICE);
//          _500
            if (skuPrice.startsWith("_")){
                rangeQueryBuilder.gte(priceArray[1]);
            }//500_
            else if (skuPrice.endsWith("_")){
                rangeQueryBuilder.lte(priceArray[0]);
            }else {
                rangeQueryBuilder.gte(priceArray[0]).lte(priceArray[1]);
            }
            boolQueryBuilder.filter(rangeQueryBuilder);
        }
        searchSourceBuilder.query(boolQueryBuilder);

        /**
         * 排序、分页、高亮
         */

        /**
         * 2.排序
         */
        String sort = searchParam.getSort();
        if (StrUtil.isNotBlank(sort)){
//            saleCount_asc
            String[] sortArray = sort.split("_");
            String sortField = sortArray[0];
            String sortType = sortArray[1];
            searchSourceBuilder.sort(sortField,SortOrder.fromString(sortType));
        }
        /**
         * 3.分页参数
         */
        Integer pageNum = searchParam.getPageNum();
        Integer from  =  (pageNum-1) * IndexConst.PRODUCT_PAGE_SIZE;
        searchSourceBuilder.size(IndexConst.PRODUCT_PAGE_SIZE);
        searchSourceBuilder.from(from);

        /**
         * 4.高亮
         */
        if (StrUtil.isNotBlank(keyword)){
            HighlightBuilder highlightBuilder = ElasticsearchUtil.builderHighlight(IndexConst.PRODUCT_SKU_TITLE);
            searchSourceBuilder.highlighter(highlightBuilder);
        }
        /**
         * 品牌 聚合分析
         */
        TermsAggregationBuilder brandAgg = AggregationBuilders.terms("brand_agg");
        brandAgg.field(IndexConst.PRODUCT_BRAND_ID).size(IndexConst.PRODUCT_AGG_MAX_SIZE);
        /**
         * 品牌_子聚合
         */
        TermsAggregationBuilder brandNameAgg = AggregationBuilders.terms("brand_name_agg");
        brandNameAgg.field(IndexConst.PRODUCT_BRAND_NAME).size(1);
        TermsAggregationBuilder brandImgAgg = AggregationBuilders.terms("brand_img_agg");
        brandImgAgg.field(IndexConst.PRODUCT_BRAND_IMG).size(1);
        brandAgg.subAggregation(brandImgAgg);
        brandAgg.subAggregation(brandNameAgg);
        searchSourceBuilder.aggregation(brandAgg);


        /**
         * 分类聚合信息
         */

        TermsAggregationBuilder catalogAgg = AggregationBuilders.terms("catalog_agg");
        catalogAgg.field(IndexConst.PRODUCT_CATALOG_ID).size(IndexConst.PRODUCT_AGG_MAX_SIZE);
        TermsAggregationBuilder catalogNameAgg = AggregationBuilders.terms("catalog_name_agg");
        catalogNameAgg.field(IndexConst.PRODUCT_CATALOG_NAME).size(1);
        catalogAgg.subAggregation(catalogNameAgg);
        searchSourceBuilder.aggregation(catalogAgg);


        /**
         * 属性聚合
         */
        NestedAggregationBuilder attrNested = AggregationBuilders.nested("attrs_agg", "attrs");
        TermsAggregationBuilder attrIdAgg = AggregationBuilders.terms("attrs_id_agg")
                .field(IndexConst.PRODUCT_ATTR_ID).size(IndexConst.PRODUCT_AGG_MAX_SIZE);



        TermsAggregationBuilder attrsNameAgg = AggregationBuilders.terms("attrs_name_agg")
                .field(IndexConst.PRODUCT_ATTR_NAME).size(1);

        TermsAggregationBuilder attrsValueAgg = AggregationBuilders.terms("attrs_value_agg");
        attrsValueAgg.field(IndexConst.PRODUCT_ATTR_VALUE).size(IndexConst.PRODUCT_AGG_MAX_SIZE);

        attrIdAgg.subAggregation(attrsNameAgg);
        attrIdAgg.subAggregation(attrsValueAgg);
        attrNested.subAggregation(attrIdAgg);
        searchSourceBuilder.aggregation(attrNested);

        SearchRequest searchRequest = new SearchRequest(IndexConst.PRODUCT_INDEX);
        searchRequest.source(searchSourceBuilder);
        log.info("DSL=============>:"+ searchSourceBuilder);
        return searchRequest;
    }

    /**
     * 构建返回结果
     * @param searchResponse
     */
    private void buildSearchResponse(SearchResponse searchResponse) {



    }

}
